/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.minidota.jetty;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParseException;
import com.minidota.game.Room;
import com.minidota.impl.PlayerImpl;
import com.minidota.jsonmodels.JsonConnect;
import com.minidota.model.BaseObject;
import com.minidota.model.Player;
import com.minidota.model.User;
import com.minidota.model.Vector2;
import com.minidota.settings.Settings;
import com.minidota.utils.Util;
import java.io.IOException;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.Date;
import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.api.WebSocketListener;
//import org.eclipse.jetty.websocket.WebSocket;

/**
 *
 * @author custom
 */
//public class GameWebSocket implements WebSocket.OnTextMessage, Runnable {    
public class GameWebSocket implements WebSocketListener, Runnable {

    public final static Gson json = new GsonBuilder().setPrettyPrinting().serializeNulls().serializeSpecialFloatingPointValues().create();
    public final static CopyOnWriteArrayList<GameWebSocket> webSockets = new CopyOnWriteArrayList<GameWebSocket>();
    private Room room;
    private User user;
    private Vector2 camera = new Vector2();
    private int screenHalfWidth = 1027;
    private int screenHalfHeight = 1027;
    /**
     * Хранилище соединения
     */
    private Session session;

    public void checkAFK() {
        /*if (System.currentTimeMillis() > lastOnline + 60 * 30 * 1000) {
         (new JobDisconnectAFK(this)).start();
         }*/
    }

    public boolean isOnScreen(BaseObject bo) {
        return Math.abs(camera.getX() - bo.getPosition().getX()) < screenHalfWidth
                && Math.abs(camera.getY() - bo.getPosition().getY()) < screenHalfHeight;
    }

    @Override
    public void onWebSocketBinary(byte[] bytes, int i, int i1) {
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onWebSocketClose(int i, String string) {
        if (getRoom() != null) {
            getRoom().disconectPlayer(user);
        }
        // Удаляем себя из глобального набора ChatWebSocketHandler::webSockets
        webSockets.remove(this);
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onWebSocketConnect(Session sn) {
        //Сохраняем соединение в свойство GameWebSocket::connection
        this.session = sn;

        // Добавляем себя в глобальный набор webSockets
        webSockets.add(this);
    }

    @Override
    public void onWebSocketError(Throwable thrwbl) {
        if ("Timeout on Read".equals(thrwbl.getMessage())) {
            if (getRoom() != null) {
                getRoom().disconectPlayer(user);
            }
            disconnect();
        } else if ("Connection has been disconnected".equals(thrwbl.getMessage())) {
            //System.out.println(Util.DATE_FORMAT.format(new Date()) + " onWebSocketError " + user.getId() + thrwbl.getMessage());
        } else {
            thrwbl.printStackTrace(System.out);
            System.out.println(Util.DATE_FORMAT.format(new Date()) + " onWebSocketError " + user.getId() + thrwbl.getMessage());
        }
        // System.out.println(Util.DATE_FORMAT.format(new Date()) + " onWebSocketError");
        //throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    @Override
    public void onWebSocketText(String string) {
        //System.out.println("msg " + string);
        onMessage(string.substring(0, 2), string.substring(2));
    }

    @Override
    public void run() {
    }

    /**
     * вызывается по приходу сообщения от клиента
     *
     * @param type - тип сообщения
     * @param data - текст сообщения
     */
    public void onMessage(String type, String data) {
        //connect
        if ("gm".equals(type)) {
            connectToRoom(data);
        } else if ("cn".equals(type) && user == null) {
            int userId = Util.tryParse(data);
            user = PlayerImpl.getInstance().getById(userId);
            if (user != null) {
                user.setSocket(this);
                //если юзер в комнате нужно его туда присоеденить.
                for (Room r : Room.roomList) {
                    if (r.isUserPresent(user.getId())) {
                        user = r.getUsers().getById(userId);
                        user.setSocket(this);
                        user.setDisconected(false);
                        room = r;
                        room.sendInitInfo(user);
                        break;
                    }
                }
            } else {
                System.out.println("ERROR CONNECT user is null " + userId);
            }
        } else if ("me".equals(type)) {
            if (getRoom() != null) {
                listenMouseEvent(data);
            }
        } else if ("ua".equals(type)) {
            if (getRoom() != null && data.length() > 0) {
                int atackUserId = data.codePointAt(0);
                if (user instanceof Player) {
                    ((Player) user).atackObject(atackUserId);
                }
            }
        } else if ("us".equals(type)) {
            if (getRoom() != null && data.length() > 0) {
                int gameId = data.codePointAt(0);
                if (user instanceof Player) {
                    ((Player) user).selectObject(gameId);
                }
            }
        } else if ("qu".equals(type)) {
            if (getRoom() != null) {
                getRoom().removeUser(user);
            }
        }
    }

    /**
     * вызывается по события нажатия/отжатия клавиш мыши
     *
     * @param mouseEvent
     */
    public void listenMouseEvent(String mouseEvent) {
        if (mouseEvent.length() >= 4) {
            String eventType = mouseEvent.substring(0, 1);
            String mouseButton = mouseEvent.substring(1, 2);
            int x = mouseEvent.codePointAt(2);
            int y = mouseEvent.codePointAt(3);

            if (user instanceof Player) {
                ((Player) user).listenMouseEvent(eventType, mouseButton, x, y);
            }
        }
    }

    /**
     * пытается зайти в комнату (если попытка не удалась, сокет-соединение
     * обрывается)
     *
     * @param data - параметры соединения
     * @return
     */
    private boolean connectToRoom(String data) {
        boolean res = false;
        if (getRoom() == null) {
            JsonConnect jc = null;
            try {
                jc = json.fromJson(data, JsonConnect.class);
            } catch (JsonParseException e) {
                System.out.println("JsonParseException: " + user.getId());
            }
            if (jc != null) {
                user.setHeroId(jc.getHeroId());
                user.setTeamId(jc.getTeamId());
                setRoom(Room.getRoomById(jc.getRoomId()));
                if (getRoom() != null) {
                    res = getRoom().addUser(user); //если юзер с таким ид в комнате уже есть то вернет false
                    if (res) {
                        user.setRoom(getRoom());
                        user.setExp(0);
                        user.relive();
                    }
                }
            }
        }
        return res;
    }

    /**
     * отправляет сообщение на клиент
     *
     * @param message
     */
    public void sendMsg(String message) {
        try {
            if (user != null && !user.isDisconected() && session.isOpen()) {
                session.getRemote().sendStringByFuture(message);
            }
        } catch (Exception ex) {
            System.out.println("SendMsg Error: " + ex.getMessage());
            disconnect();
        }
    }

    public void disconnect() {
        try {
            session.disconnect();
        } catch (IOException ex) {
            System.out.println("disconnect: " + ex.getMessage());
        }
    }

    /**
     * отправляет сообщение на клиент
     *
     * @param data - текст сообщения
     * @param type - тип сообщения
     */
    public void sendMsg(String type, String data) {
        sendMsg(type + data);
    }

    public User getUser() {
        return user;
    }

    /**
     * @return the room
     */
    public Room getRoom() {
        return room;
    }

    /**
     * @param room the room to set
     */
    public void setRoom(Room room) {
        this.room = room;
    }
}
